import axios, {
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
import { storeToRefs } from 'pinia'
import { useMenuStore } from '@/store/modules/menu'
import { showStatus } from './common'
import qs from 'qs'
import { ElMessage } from 'element-plus'

// 声明一个 Map 用于存储每个请求的标识 和 取消函数
const pending = new Map()

/**
 * 添加请求
 * @param {Object} config
 */
const addPending = (config: AxiosRequestConfig) => {
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data),
  ].join('&')
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      if (!pending.has(url)) {
        // 如果 pending 中不存在当前请求，则添加进去
        pending.set(url, cancel)
      }
    })
}
/**
 * 移除请求
 * @param {Object} config
 */
const removePending = (config: AxiosRequestConfig) => {
  const url = [
    config.method,
    config.url,
    qs.stringify(config.params),
    qs.stringify(config.data),
  ].join('&')
  if (pending.has(url)) {
    // 如果在 pending 中存在当前请求标识，需要取消当前请求，并且移除
    const cancel = pending.get(url)
    cancel(url)
    pending.delete(url)
  }
}

/**
 * 清空 pending 中的请求（在路由跳转时调用）
 */
export const clearPending = () => {
  for (const [url, cancel] of pending) {
    cancel(url)
  }
  pending.clear()
}

axios.defaults.headers.post['Content-Type'] =
  'application/x-www-form-urlencoded;charset=UTF-8'
// axios.defaults.transformRequest = [
//   (data, config) => {
//     const contentType = config['Content-type'] + ''
//     switch (contentType.toLowerCase()) {
//       case 'application/json;charset=utf-8':
//         return JSON.stringify(data) // 序列化结果 ："{"a":"hehe","age":10}"
//       case 'multipart/form-data;charset=utf-8':
//         return data // 文件不做处理
//       default:
//         return qs.stringify(data) // 序列化结果 ：name=hehe&age=10
//     }
//   }
// ]

const axiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL?.toString(), // 基础路径
  withCredentials: true, // 是否跨站点访问控制请求
  timeout: 300000,
  // transformRequest: [
  //   (data, config) => {
  //     // 表示允许在向服务器发送前，修改请求数据
  //     console.log('向服务器发送前，修改请求数据 -> ', data)
  //     return JSON.stringify(data)
  //   }
  // ],
  // `onUploadProgress` 允许为上传处理进度事件
  onUploadProgress: function (progressEvent) {
    // 对原生进度事件的处理
    console.log('onUploadProgress', progressEvent)
  },
  // `onDownloadProgress` 允许为下载处理进度事件
  onDownloadProgress: function (progressEvent) {
    // 对原生进度事件的处理
    console.log('onDownloadProgress', progressEvent)
  },
  // validateStatus 函数返回true时，
  // response会出现在 instance.interceptors.response.use（successCallBack, errorCallBack） 的successCallBack；
  // 为 false时，会出现在 errorCallBack中。
  validateStatus(status: number) {
    return status === 200 // 拦截非200的请求
  },
  transformResponse: [
    (data) => {
      // 在传递给 then/catch 前，允许修改响应数据
      if (typeof data === 'string' && data.startsWith('{')) {
        data = JSON.parse(data)
      }
      return data
    },
  ],
})

// request 不支持泛型
// request .get、post、put等 支持泛型

// 请求拦截器
axiosInstance.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    removePending(config) // 在请求开始前，对之前的请求做检查取消操作
    addPending(config) // 将当前请求添加到 pending 中
    // 统一设置用户身份 token
    // 获取token，并将其添加至请求头中
    const token = localStorage.getItem('token')
    if (token && config.headers) {
      config.headers.Authorization = `${token}`
    }

    const menuStore = useMenuStore()
    const { user } = storeToRefs(menuStore)
    if (user && user.value?.token && config.headers) {
      config.headers.Authorization = `Bearer ${user.value?.token}`
    }
    return config
  },
  (error) => {
    error.data = {}
    error.data.msg = '服务器异常,请联系管理员'
    return Promise.reject(error)
  },
)

// 响应拦截器
axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    removePending(response) // 在请求结束后，移除本次请求
    // 统一处理响应错误，例如token失效，服务端异常等
    const status = response.status
    let msg = ''
    if (status < 200 || status >= 300) {
      // 处理http错误，抛到业务代码
      msg = showStatus(status)
      if (typeof response.data === 'string') {
        response.data = { msg }
      } else {
        response.data.msg = msg
      }
    }
    return response
  },
  (error) => {
    if (axios.isCancel(error)) {
      console.log('repeated request: ' + error.message)
    } else {
      // handle error code
      // 错误抛到业务代码
      error.data = {}
      error.data.msg = '请求超时或服务器异常，请检查网络或联系管理员！'
      ElMessage.error(error.data.msg)
    }
    return Promise.reject(error)
  },
)

/**
 * 返回一个函数再包多一层，支持泛型
 * @param config 请求配置项
 * @returns 泛型T
 */
export const request = <T = any>(config: AxiosRequestConfig) => {
  return axiosInstance(config).then((res) => {
    console.log('请求返回结果 ->', res.data || res.data.data)
    return (res.data || res.data.data) as T
  })
}
/**
 * 请求上传文件
 * @param config 请求配置项
 * @returns 泛型T
 */
export const uploadRequest = <T = any>(config: AxiosRequestConfig) => {
  return axiosInstance(config).then((res) => {
    console.log('文件上传返回结果 ->', res.data || res.data.data)
    return (res.data || res.data.data) as T
  })
}
